﻿using UnityEngine;
using System;
namespace PBRSystem.Coord
{
    public class PBRPoint3
    {

        #region Variables
        private float _x, _y, _z;
        #endregion

        #region Contructor
        public PBRPoint3()
        {
            _x = _y = _z = 0;
        }

        public PBRPoint3(PBRPoint3 point)
        {
            _x = point.X;
            _y = point.Y;
            _z = point.Z;
        }

        public PBRPoint3(float x, float y, float z)
        {
            _x = x;
            _y = y;
            _z = z;
        }

        #endregion

        #region Reporter
        public float X { get => _x; set => _x = value; }
        public float Y { get => _y; set => _y = value; }
        public float Z { get => _z; set => _z = value; }
        #endregion

        #region Operator
        public static PBRPoint3 operator +(PBRPoint3 a, PBRPoint3 b)
        {
            return new PBRPoint3(a.X + b.X, a.Y + b.Y, a.Z + b.Z);
        }

        public static PBRPoint3 operator +(PBRPoint3 a, PBRVector3 b)
        {
            return new PBRPoint3(a.X + b.X, a.Y + b.Y, a.Z + b.Z);
        }

        public static PBRVector3 operator -(PBRPoint3 a, PBRPoint3 b)
        {
            return new PBRVector3(a.X - b.X, a.Y - b.Y, a.Z - b.Z);
        }

        public static PBRPoint3 operator -(PBRPoint3 a, PBRVector3 b)
        {
            return new PBRPoint3(a.X - b.X, a.Y - b.Y, a.Z - b.Z);
        }

        public static PBRPoint3 operator -(PBRPoint3 a, float s)
        {
            return new PBRPoint3(a.X * s, a.Y * s, a.Z * s);
        }

        public static PBRPoint3 operator -(PBRPoint3 a)
        {
            return new PBRPoint3(-a.X, -a.Y, -a.Z);
        }

        public static PBRPoint3 operator *(PBRPoint3 a, float s)
        {
            return new PBRPoint3(a.X * s, a.Y * s, a.Z * s);
        }

        public static PBRPoint3 operator /(PBRPoint3 a, float s)
        {
            if(s == 0)
            {
                return a;
            }

            return new PBRPoint3(a.X / s, a.Y / s, a.Z / s);
        }

        public static bool operator ==(PBRPoint3 a, PBRPoint3 b)
        {
            return (a.X == b.X) && (a.Y == b.Y) && (a.Z == b.Z);
        }

        public static bool operator !=(PBRPoint3 a, PBRPoint3 b)
        {
            return (a.X != b.X) || (a.Y != b.Y) || (a.Z != b.Z);
        }



        #endregion

        #region Override
        public override bool Equals(object obj)
        {
            if (!(obj is PBRPoint3))
            {
                return false;
            }

            PBRPoint3 p = (PBRPoint3)obj;
            return (_x == p.X) && (_y == p.Y) && (_z == p.Z);
        }


        public override int GetHashCode()
        {
            return base.GetHashCode();
        }
        #endregion

        #region Operation
        public PBRPoint3 Min(PBRPoint3 p1, PBRPoint3 p2)
        {
            return new PBRPoint3(Math.Min(p1.X, p2.X), Math.Min(p1.Y, p2.Y), Math.Min(p1.Z, p2.Z));
        }

        public PBRPoint3 Max(PBRPoint3 p1, PBRPoint3 p2)
        {
            return new PBRPoint3(Math.Max(p1.X, p2.X), Math.Max(p1.Y, p2.Y), Math.Max(p1.Z, p2.Z));
        }

        public PBRPoint3 Floor(PBRPoint3 p)
        {
            return new PBRPoint3((float)Math.Floor(p.X), (float)Math.Floor(p.Y), (float)Math.Floor(p.Z));
        }

        public PBRPoint3 Ceil(PBRPoint3 p)
        {
            return new PBRPoint3((float)Math.Ceiling(p.X), (float)Math.Ceiling(p.Y), (float)Math.Ceiling(p.Z));
        }

        public PBRPoint3 Abs(PBRPoint3 p)
        {
            return new PBRPoint3((float)Math.Abs(p.X), (float)Math.Abs(p.Y), (float)Math.Abs(p.Z));
        }

        public static float Distance(PBRPoint3 p1, PBRPoint3 p2)
        {
            return (p1 - p2).Length();
        }

        public static float DistanceSquared(PBRPoint3 p1, PBRPoint3 p2)
        {
            return (p1 - p2).LengthSquard();
        }

        public bool HasNaNs()
        {
            return float.IsNaN(_x) && float.IsNaN(_y) && float.IsNaN(_z);
        }


        #endregion
    }
}
    
